/////precompiled////////
#include "precompiled.h"
////////////////////////


#include "frm_control_TPara.h"
#include "frm_control_TString.h"
#include "frm_control_TParaEdit.h"

using namespace frm;
using namespace control;

// TPara //////////////////////////////////////////////////////////////////////

//
void TPara::TStyle::SetFromParent(frm::TStyle *Parent_)
{
  if (!Parent_) {
    return;
  }

  TStyle *Parent = dynamic_cast<TStyle*>(Parent_);
  
  Normal.Filler.SetFromParent(Parent->Normal.Filler);
  Normal.Cursor.SetFromParent(Parent->Normal.Cursor);
  Normal.Border.SetFromParent(Parent->Normal.Border);

  Selected.Filler.SetFromParent(Parent->Selected.Filler);
  Selected.Cursor.SetFromParent(Parent->Selected.Cursor);
  Selected.Border.SetFromParent(Parent->Selected.Border);

  Focused.Filler.SetFromParent(Parent->Focused.Filler);
  Focused.Cursor.SetFromParent(Parent->Focused.Cursor);
  Focused.Border.SetFromParent(Parent->Focused.Border);
  
  Line.SetFromParent(&Parent->Line);
}

//
svl::TInfoParam TPara::TStyle::AddInfoTo(svl::TInfoParam Info)
{
  return frm::TStyle::AddInfoTo(Info)
   .Add("Normal"   ,Normal)
   .Add("Selected",Selected)
   .Add("Focused" ,Focused)
   .Add("Line"    ,Line)
  ;
}

//
TPara::TPara(TWindow &Window) : TPanel(Window)
{
  struct TStyle : public TPara::TStyle
  {
    TStyle()
    {
      //Focused.Filler.Set(filler::TFrameRect(192,192,0));
      
      Focused.Filler.Set(filler::TArray()
        .Add(filler::TColor    (230,230,230))
        .Add(filler::TFrameRect(192,192,0))
      );
    }    
  };
  static TStyle Style;

  SetEnProcChangeWidth(); 
  SetEnFormatting();

  Width_Fixed(200).Height_ChildrenSum()
   .DirectChildren_Vert()
   .WAlignChildren_Begin().HAlignChildren_Begin();


  FirstLine = NewLine(); 
  AddChildLast(FirstLine,true);

  FirstLine->Width_Parent()/*ChildrenSum()*/.Height_ChildrenMaxBase()
   .DirectChildren_Horz()
   .WAlignChildren_Begin().HAlignChildren_BeginBase();

  SetStyle(Style); 
}

//
TPara::~TPara()
{
  DeleteChildren();
}

//
TPara &TPara::SetStyle(TStyle &V)
{
  style = &V; 
  FirstLine->SetStyle(V.Line);
  
  if (IsVisibleInParents())  {
    if (Focus_IsEnter()) { 
      TPanel::UpdateStyle(V.Focused); 
    }
    else if (Select_IsEnter()) { 
      TPanel::UpdateStyle(V.Selected); 
    }
    else { 
      TPanel::UpdateStyle(V.Normal); 
    }
  }
  else { 
    TPanel::SetStyle(V.Normal); 
  }
  
  return *this;
}

//
void TPara::SetEnFormatting(bool V)
{
  enFormatting = V;
}

//
void TPara::TComponent_Mouse(TMouse Mouse)
{
  switch (Mouse.State)
  {
    case grf::TMouse::EState_LButtonDown: if
    (
      //Mouse.TopComponent == this &&
      TComponent_FocusEnable() && 
      Mouse.TopComponent->TComponent_TransparentForFocus()
    )
    {
    
      //::MessageBeep(0);
    
      //Focus_SetByPos(0); return;
    }
    break;
  }
  TPanel::TComponent_Mouse(Mouse);
}

//
void TPara::TComponent_KeyboardKey(grf::TKeyboardKey &KeyboardKey)
{
  if (KeyboardKey.State == grf::TKeyboardKey::EState_Down)
  {
    switch (KeyboardKey.Key)
    {
      case VK_UP: case VK_DOWN:
      {
        TPanel *CurrFocus = Focus_GetEnter();

        TPanel *CurrLine = dynamic_cast<TPanel*>(
          CurrFocus->SearchThisOrParent(TLine::TType())
        );
        if (!CurrLine) { break;}

        TPanel *NewLine = KeyboardKey.Key == VK_UP
          ? SearchPrevChild(TLine::TType(),CurrLine)
          : SearchNextChild(TLine::TType(),CurrLine);
        if (!NewLine) { break;}

        TPanel *NewFocus = NewLine->SearchNextChild
          (TString::TType(),NULL);
        if (!NewFocus) { break;}

        NewFocus->Focus_EnterByX(Focus_GetX());
      }
      return;

      case VK_PRIOR: case VK_NEXT:
      {
        if (!Options.EnProcKeyPgUp_KeyPgDown)
          { break; }
      
        TPanel *CurrFocus = Focus_GetEnter();

        TPanel *CurrLine = dynamic_cast<TPanel*>(
          CurrFocus->SearchThisOrParent(TLine::TType())
        );
        if (!CurrLine) { break;}

        TGeometryRect ParaGRect; if
          ( !GetWindow().CalcGeometryRect(this,ParaGRect) )
        { break;}

        TPanel *NewLine = dynamic_cast<TPanel*>(
          KeyboardKey.Key == VK_PRIOR
            ? SearchPrevChildInHeight(ParaGRect,CurrLine)
            : SearchNextChildInHeight(ParaGRect,CurrLine)
        );
        if (!NewLine) { break;}

        TPanel *NewFocus = NewLine->SearchNextChild
          (TString::TType(),NULL);
        if (!NewFocus) { break;}

        NewFocus->Focus_EnterByX(Focus_GetX());
      }
      return;


      case VK_DELETE: if (KeyboardKey.Shift.IsEmpty())
      {
        TPanel *CurrFocus = Focus_GetEnter();

        TLine *CurrLine = dynamic_cast<TLine*>
          ( CurrFocus->SearchThisOrParent(TLine::TType()) );
        if (!CurrLine) { break;}

        int NCurrLine = GetNChild(CurrLine); if (NCurrLine + 1 == GetChildrenCount())
          { break; }
          
/***********************          
          TPara *NextPara = dynamic_cast<TPara*>
            ( GetParent()->SearchNextChild(TPara::TType(),this) );
          if (!NextPara) { break;}

          if (NextPara->ChildrenCount() > 0)
          {
            Paint_Begin();
            NextPara->MoveChildrenTo(0,NextPara->ChildrenCount()-1,NCurrLine+1,this);
            GetGeometry().CalcAll();
            GetParent()->DeleteChild(NextPara);
            Paint_End();
          }
*********************/          
        
        if (GetChildrenCount() == 0) { 
          break; 
        }

        TLine *NextLine = dynamic_cast<TLine*>(&GetChild(NCurrLine+1));
        TPanel *C = NextLine->SearchNextChildFocusEnable(TString::TType()); 
        
        if (C && C->DeleteSymbolInPos(0)) { 
          BeginPaint();
          CalcAllSize(); 
          EndPaint();
        }
      }
      return;

      case VK_BACK: {
        TPanel *CurrFocus = Focus_GetEnter();

        TLine *CurrLine = dynamic_cast<TLine*>( 
          CurrFocus->SearchThisOrParent(TLine::TType())
        );
        if (!CurrLine) { 
          break;
        }
        
        int NCurrLine = GetNChild(CurrLine); 
        if (NCurrLine == 0) { 
          break; 
        }

        TLine *PrevLine = dynamic_cast<TLine*>(&GetChild(NCurrLine-1));
        TPanel *C = PrevLine->SearchPrevChildFocusEnable(TString::TType()); 
        
        if (C) {
          BeginPaint();
          int MaxPos = C->TComponent_GetCaretMaxPos(); 
          if (C->DeleteSymbolInPos(MaxPos-1)) { 
            C->Focus_EnterByPos(MaxPos-1); 
          }
          EndPaint();
        }
      }
      return;
    }
  }
  TPanel::TComponent_KeyboardKey(KeyboardKey);
}

//
void TPara::TComponent_SelectEnter()
{
  TPanel::TComponent_SelectEnter(); 
  
  if (!Focus_IsEnter()) { 
    TPanel::UpdateStyle(style->Selected);
  }
}

//
void TPara::TComponent_SelectExit()
{
  TPanel::TComponent_SelectExit();
  TPanel::UpdateStyle(style->Normal);
}

//
void TPara::TComponent_FocusEnter()
{
  TPanel::TComponent_FocusEnter();

  TPanelSelect *Select = GetSelectThisOrParent();
  if (Select) { Select->SetEnter(this);}
  TPanel::UpdateStyle(style->Focused);
}

//
void TPara::TComponent_FocusExit()
{
  TPanel::TComponent_FocusExit();

  TPanelSelect *Select = GetSelectThisOrParent();
  if (Select && Select->IsEntered(this))
    { TPanel::UpdateStyle(style->Selected);}
  else
    { TPanel::UpdateStyle(style->Normal);}
}

//
void TPara::TComponent_InheritStyleFrom(TTableOfStyles &ParentStyles)
{ 
  TStyle *Style = dynamic_cast<TStyle*>(ParentStyles.SearchByEqualType(TStyle::TType())); if (Style) {
    SetStyle(*Style);
  }
}

//
void TPara::Clear()
{
  TBeginPaint BP(this);
  TTempDisableFormatting DF(this);

  while (GetChildrenCount() > 1) {
    DeleteChild(1);
  }
  FirstLine->DeleteChildren();

  if (IsVisibleInParents()) { 
    CalcAllSize(); /*GetHOrdinate().*/ReupdateSize();
  }

/***************
  bool IsVisible        = this->IsVisibleInParents();
  bool SaveEnFormatting = enFormatting; enFormatting = false;

  if (IsVisible) { BeginPaint();}

  while (GetChildrenCount() > 1)
  {
    DeleteChild(1);
  }
  FirstLine->DeleteChildren();

  if (IsVisible) { CalcAllSize(); GetHOrdinate().ReupdateSize();}

  enFormatting = SaveEnFormatting; //Formatting();

  if (IsVisible) { EndPaint();}
*************/  
}

//
TLine *TPara::NewLine()
{
  TLine *Line = new TLine(GetWindow());
  
  struct TStyle : public TLine::TStyle
  {
    TStyle()
    {
      //Focused.Filler.Set(filler::TFrameRect(192,192,0));
      
      Focused.Filler.Set(filler::TArray()
        .Add(filler::TColor    (220,220,220))
        .Add(filler::TFrameRect(192,192,0))
      );
    }    
  };
  static TStyle Style; Line->SetStyle(Style);
  
  return Line;
}

//
void TPara::Formatting(int ParaWidth)
{
  if (!GetEnFormatting()) { 
    return;
  }
  if (svl::TPStack::IsTop(this)) { 
    return;
  }
  svl::TPStack PStack(this);

  TMergeSplit MS;
    MS.Focus = Focus_GetEnter();
    MS.Pos   = Focus_GetPos();
  
  bool IsChange = false;
  TBeginPaint BP(this);
  
  if (!ThisIsParent(MS.Focus)) {
    MS.Focus = NULL;
    MS.Pos = 0;
  }
  else {
    Focus_Enter();
  }

  if (GetChildrenCount()) {
    TTempDisableCalcSize D(this);
    TTempNotVisible TNV(this);
  
    // merge ///////////////////
    TLine *CurrLine = FirstLine;
    
    while (GetChildrenCount() > 1) {
      TLine *Line = dynamic_cast<TLine*>(&GetChild(1));
      CurrLine->Merge(MS,*Line);
      
      GetWindow().PanelDeletor.Add(this,1);
      //DeleteChild(1);
      IsChange = true;
    }

    // split ///////////////////////////////
    //while (CurrLine->GetWidth() > ParaWidth)
    while (
      CurrLine->GetWOrdinate().CalcChildrenSumSize()
      + CurrLine->GetGeometry().GetWBorder()->GetSize()
      > ParaWidth
    ){
      TLine *NextLine = NewLine();

      NextLine->GetGeometry().CopyBorderFrom        (CurrLine->GetGeometry());
      NextLine->GetGeometry().CopyCalcSizeFrom      (CurrLine->GetGeometry());
      NextLine->GetGeometry().CopyDirectChildrenFrom(CurrLine->GetGeometry());
      NextLine->GetGeometry().CopyAlignChildrenFrom (CurrLine->GetGeometry());

      NextLine->SetStyle(FirstLine->GetStyle());
      
      if (CurrLine->Split(MS,*NextLine,ParaWidth)) {
        AddChildAfter(NextLine,CurrLine);
        
        CurrLine = NextLine;
        IsChange = true;
      }
      else {
        delete NextLine;
        break;
      }
    }
  }

  if (IsChange) {
    CalcAllSize();
    ReupdateSize();
  }

  if (ThisIsParent(MS.Focus)) {
    if (MS.Focus->Focus_EnterByPos(MS.Pos)) { 
      MS.Focus->Focus_FixCaretX(); 
    }
  }
}

//
void TPara::Child_AfterChangeWidth(int OldVal,int NewVal)
{
  if (OldVal == NewVal) { 
    return;
  }
  if (!svl::TPStack::IsTop(this) && IsVisibleInParents()) { 
    new TPostFormatting(*this);
  }
}

//
void TPara::TComponent_AfterChangeWidth(int OldVal,int NewVal)
{
  TPanel::TComponent_AfterChangeWidth(OldVal,NewVal);

  if (!enProcChangeWidth) { 
    return;
  }
  if (OldVal == NewVal)  { 
    return;
  }
  if (!svl::TPStack::IsTop(this) && IsVisibleInParents()) { 
    Formatting();
  }
}

//
void TPara::TComponent_AddToParent(TComponent *Parent)
{
  TPanel::TComponent_AddToParent(Parent);

  TParaEdit *ParaEdit = dynamic_cast<TParaEdit*>(SearchParent(TParaEdit::TType())); 
  if (ParaEdit) {
    SetEnProcChangeWidth(false);
    SetEnFormatting(ParaEdit->GetEnFormatting());
  }
}

// TPostFormatting ////////////////////////////////////////////////////////////

//
TPara::TPostFormatting::TPostFormatting(TPara &Para) : para(Para)
{
  para.BeginPaint(); Post();
}

//
void TPara::TPostFormatting::TPostMessage_Receive()
{
  para.Formatting(); para.EndPaint();
}

